package com.ciwong.mobilelib.widget.listview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListAdapter;
import android.widget.ListView;



/**
 * 支持下拉刷新,加载更多的ListView
 *
 * @author     res-jianpingliu
 * @version    ciwong v.1.0 2014-9-13
 * @since      ciwong v.1.0
 *
 */
public class PullRefreshListView extends ListView implements OnScrollListener
{
    protected OnScrollListener mScrollListener; // user's scroll listener

    protected PullRefreshController pullRefreshController;

    /**
     *
     * 支持下拉刷新,加载更多的ListView
     *
     * @param context
     *            上下文
     */
    public PullRefreshListView(Context context)
    {
        super(context);
        initWithContext(context);
    }

    /**
     *
     * 支持下拉刷新,加载更多的ListView
     *
     * @param context
     *            上下文
     * @param attrs
     *            属性集合
     */
    public PullRefreshListView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        initWithContext(context);
    }

    /**
     *
     * 支持下拉刷新,加载更多的ListView
     *
     * @param context
     *            上下文
     * @param attrs
     *            属性集合
     * @param defStyle
     *            样式
     */
    public PullRefreshListView(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
        initWithContext(context);
    }

    private void initWithContext(Context context)
    {
        pullRefreshController = new PullRefreshController(this);
        // XListView need the scroll event, and it will dispatch the event to
        // user's listener (as a proxy).
        super.setOnScrollListener(this);

        setOverScrollMode(OVER_SCROLL_NEVER);

        PullRefreshController.CWListViewHeader headerView = pullRefreshController.getHeaderView();
        addHeaderView(headerView);
        // init header height
        getViewTreeObserver().addOnGlobalLayoutListener(
                new OnGlobalLayoutListener()
                {
                    @Override
                    public void onGlobalLayout()
                    {
                        if (pullRefreshController.isShowHeader())
                        {
                            showHeader();
                        }
                        getViewTreeObserver()
                                .removeGlobalOnLayoutListener(this);
                    }
                });
    }

    @Override
    public void setAdapter(ListAdapter adapter)
    {
        // make sure CWListViewFooter is the last footer view, and only add
        // once.
        if (!pullRefreshController.isFooterReady() && pullRefreshController.isEnablePullLoad())
        {
            pullRefreshController.setFooterReady(true);
            addFooterView(pullRefreshController.getFooterView(),null,true);
        }
        super.setAdapter(adapter);
    }

    /**
     * 禁止下拉刷新和加载更多功能
     *
     */
    public void freezeRefreshAndLoadMore()
    {
        pullRefreshController.freezeRefreshAndLoadMore();
    }

    /**
     * 是否开启下拉刷新的功能
     *
     * @param enable
     *            是否能用
     */
    public void setPullRefreshEnable(boolean enable)
    {
        pullRefreshController.setPullRefreshEnable(enable);
    }

    /**
     * 是否开启加载更多的功能
     *
     * @param enable
     *            是否能用
     */
    public void setPullLoadEnable(boolean enable)
    {
        pullRefreshController.setPullLoadEnable(enable);
    }

    /**
     * 是否正在刷新
     *
     * @return 是否正在刷新
     */
    public boolean isRefreshing()
    {
        return pullRefreshController.isRefreshing();
    }

    /**
     *  停止刷新
     */
    public void stopRefresh()
    {
        pullRefreshController.stopRefresh();
    }

    /**
     * 停止刷新
     *
     * @param showFooter
     *            是否显示底部视图
     */
    public void stopRefresh(boolean showFooter)
    {
        pullRefreshController.stopRefresh(showFooter);
    }

    /**
     * 停止加载更多
     */
    public void stopLoadMore()
    {
        pullRefreshController.stopLoadMore();
    }

    /**
     * 停止加载更多
     *
     * @param showFooter
     *            是否显示底部视图
     */
    public void stopLoadMore(boolean showFooter)
    {
        pullRefreshController.stopLoadMore(showFooter);
    }

    /**
     * 加载更多失败
     */
    public void failLoadMore()
    {
        pullRefreshController.failLoadMore();
    }

    /**
     * 自定义刷新时间
     *
     * @param time
     *            刷新时间
     */
    public void setRefreshTime(String time)
    {
        pullRefreshController.setRefreshTime(time);
    }

    /**
     * 开始刷新
     *
     */
    public void startRefresh()
    {
        pullRefreshController.startRefresh();
    }

    /**
     * 设置刷新时间
     */
    public void setRefreshTime()
    {
        pullRefreshController.setRefreshTime();
    }

    private void updateHeaderHeight(float delta)
    {
        pullRefreshController.updateHeaderHeight(delta);
        setSelection(0); // scroll to top each time
    }

    /**
     * 重置下拉刷新的头高度
     */
    public void resetHeaderHeight()
    {
        pullRefreshController.resetHeaderHeight();
    }

    /**
     * 显示下拉刷新的头
     */
    public void showHeader()
    {
        setRefreshTime();
        pullRefreshController.setShowHeader(true);
        pullRefreshController.setHeaderVisiableHeight(pullRefreshController.getHeaderVisiableHeight());
        resetHeaderHeight();
    }

    /**
     * 显示加载更多
     *
     */
    public void showFooter()
    {
        pullRefreshController.showFooter();
    }

    /**
     * 隐藏加载更多
     *
     */
    public void hideFooter()
    {
        pullRefreshController.hideFooter();
    }

    /**
     * 禁止下拉刷新
     *
     */
    public void freezeRefresh()
    {
        pullRefreshController.freezeHeader();
    }

    /**
     * 禁止加载更多
     *
     */
    public void freezeLoadMore()
    {
        pullRefreshController.freezeFooter();
    }

    /**
     * 设置下拉刷新、加载更多的监听器
     *
     * @param l 监听器
     */
    public void setPullRefreshListener(PullRefreshController.PullRefreshListener l)
    {
        pullRefreshController.setPullRrefreshListener(l);
    }

    private void updateFooterHeight(float delta)
    {
        int height = Math.abs(getScrollY());
        delta = pullRefreshController.updateFooterHeight(height, delta);
        scrollBy(0, (int) delta);
    }

    private boolean resetFooterHeight()
    {
        if (getScrollY() > 0)
        {
            pullRefreshController.setLastY(0);
            pullRefreshController.setScrollBack(PullRefreshController.SCROLLBACK_FOOTER);
            pullRefreshController.getScroller().startScroll(0, getScrollY(), 0, -getScrollY(),
                    PullRefreshController.SCROLL_DURATION);
            invalidate();
            return true;
        }
        return false;
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev)
    {
        if (ev.getPointerCount() > 1)
        {
            return true;
        }
        if (pullRefreshController.getLastY() == -1)
        {
            pullRefreshController.setLastY(ev.getRawY());
        }
        switch (ev.getAction())
        {
            case MotionEvent.ACTION_DOWN:
                pullRefreshController.setLastY(ev.getRawY());
                if (!pullRefreshController.getScroller().isFinished())
                {
                    pullRefreshController.getScroller().abortAnimation();
                }
                if (getLastVisiblePosition() == pullRefreshController.getTotalItemCount() - 1)
                {
                    return true;
                }
                break;
            case MotionEvent.ACTION_MOVE:
                float deltaY = ev.getRawY() - pullRefreshController.getLastY();
                pullRefreshController.setLastY(ev.getRawY());
                // Log.d("debug", "--ACTION_MOVE");
                if (getFirstVisiblePosition() == 0
                        && (pullRefreshController.getHeaderVisiableHeight() > 0 || deltaY > 0)
                        && getScrollY() == 0)
                {
                    // the first item is showing, header has shown or pull down.
                    updateHeaderHeight(deltaY / PullRefreshController.OFFSET_RADIO);
                    if (!pullRefreshController.isHeaderScroll())
                    {
                        setRefreshTime();
                        pullRefreshController.setHeaderScroll(true);
                    }
                    pullRefreshController.setScrollBack(PullRefreshController.SCROLLBACK_HEADER);
                    // Log.d("debug", "--SCROLLBACK_HEADER scrollY:"
                    // + getScrollY());
                }
                else if (getLastVisiblePosition() == pullRefreshController.getTotalItemCount() - 1)
                {
                    // last item, already pulled up or want to pull up.
                    View view = getChildAt(getChildCount() - 1);
                    if (view != null
                            && (deltaY < 0 || (pullRefreshController.getFooterState() == PullRefreshController.CWListViewFooter.STATE_READY))
                            && pullRefreshController.isFooterVisiable())
                    {
                        boolean isBottom = view.getBottom() == pullRefreshController.getLastBottom();
                        pullRefreshController.setLastBottom(view.getBottom());

                        if (isBottom)
                        {
                            if (getScrollY() >= 0)
                            {
                                updateFooterHeight(-deltaY / PullRefreshController.OFFSET_RADIO);
                            }
                            else
                            {
                                scrollTo(0, 0);
                            }
                        }
                    }
                }
                else
                {
                    // Log.d("debug", "--scrollY:"+getScrollY());
                    pullRefreshController.setScrollBack(PullRefreshController.SCROLLBACK_NONE);
                }
                if (getScrollY() > 0)
                {
                    pullRefreshController.setScrollBack(PullRefreshController.SCROLLBACK_FOOTER);
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                pullRefreshController.setHeaderScroll(false);
            default:
                pullRefreshController.setLastY(-1);// reset
                if (pullRefreshController.getScrollBack() == PullRefreshController.SCROLLBACK_HEADER)
                {
                    // invoke refresh
                    if (pullRefreshController.isEnablePullRefresh()
                            && pullRefreshController.getHeaderVisiableHeight()
                            > pullRefreshController.getHeaderViewHeight())
                    {
                        startRefresh();
                    }
                    resetHeaderHeight();
                }
                else if (pullRefreshController.getScrollBack() == PullRefreshController.SCROLLBACK_FOOTER)
                {
                    // invoke load more.
                    if (pullRefreshController.isEnablePullLoad()
                            && getScrollY() > PullRefreshController.PULL_LOAD_MORE_DELTA)
                    {
                        pullRefreshController.startLoadMore();
                    }
                    boolean temp = resetFooterHeight();
                    if (temp)
                    {
                        return true;
                    }
                }
                break;
        }

        return super.onTouchEvent(ev);
    }

    @Override
    public void computeScroll()
    {
        if (pullRefreshController.getScroller().computeScrollOffset())
        {
            if (pullRefreshController.getScrollBack() == PullRefreshController.SCROLLBACK_HEADER)
            {
                pullRefreshController.setHeaderVisiableHeight(pullRefreshController.getScroller().getCurrY());
            }
            else
            {
                scrollTo(0, pullRefreshController.getScroller().getCurrY());
            }
            postInvalidate();
        }
    }

    @Override
    public void setOnScrollListener(OnScrollListener l)
    {
        mScrollListener = l;
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState)
    {
        if (mScrollListener != null)
        {
            mScrollListener.onScrollStateChanged(view, scrollState);
        }
    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount)
    {
        pullRefreshController.setTotalItemCount(totalItemCount);
        if (mScrollListener != null)
        {
            mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount,
                    totalItemCount);
        }
    }

    public void showHeaderSpliteLine(boolean need)
    {
        pullRefreshController.showHeaderSpliteLine(need);
    }
}
